home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / cc04.arc / YARCOUT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1986-03-15  |  17.3 KB  |  896 lines

  1. /*
  2.     NetWare Archive to Alloy - File List output Module
  3.     V4.42    02/04/84    by Mark Hurst, Kyle Powell
  4.  
  5.     For use with NetWare V4.n systems
  6.  
  7.     Copyright (C) 1983, 1984 Novell, Inc.
  8. */
  9.  
  10. #include    "ctype.h"
  11. #include    "stdio.h"
  12.  
  13.  
  14. #define LOCALBIT    0x80
  15. #define    PERMNET        0x01
  16. #define    TEMPNET        0x02
  17. #define    NETBITS        0x03
  18.  
  19. #define    READBIT        0x01
  20. #define    WRITEBIT    0x02
  21. #define    OPENBIT        0x04
  22. #define    CREATEBIT    0x08
  23. #define    DELETEBIT    0x10
  24. #define    OWNEDBIT    0x20
  25. #define    SEARCHBIT    0x40
  26. #define    MODIFYBIT    0x80
  27.  
  28. /* NOTE: the Archive bit was 0x80 on ShareNet V3.12.  Has now changed: */
  29. #define BACKUPBIT    0x20
  30. #define    LASTBIT        0x10
  31.  
  32. extern    unsigned DOS11, DOS20;
  33. unsigned unitsize;
  34. unsigned fileswritten;
  35.  
  36. #define        VARPATH        '^' - 'A'
  37.  
  38. #define        TRUE        1
  39. #define        FALSE        0
  40.  
  41. #define        MAXVOLUMES    16
  42. #define        MAXSPECS    100
  43.  
  44. #define        ALLMODE        1
  45. #define        MODMODE        2
  46. #define        SELMODE        3
  47.  
  48.  
  49. FILE    *log;
  50. int    source, target; /* low level I/O file numbers */
  51.  
  52. extern    char    actarget[20];
  53. extern    char    inline[80];
  54.  
  55. extern    int    printlog, spool, saverights;
  56. int    nprinter, logcopies;
  57. extern    int    startup;
  58.  
  59.  
  60. extern    int    numberqualified, numberout;
  61. char    *calloc(), *malloc();
  62.  
  63. extern    unsigned known, firsttypecheck, unusabledisk;
  64.  
  65. typedef struct dosfcb {
  66.     char    drive;
  67.     char    fname[8];
  68.     char    fext[3];
  69.     unsigned curblk;
  70.     unsigned recsize;
  71.     long    size;
  72.     unsigned date;
  73.     char    reserved[10];
  74.     char    relrec;
  75.     char    record[4];
  76. } FCB;
  77.  
  78. typedef    struct exdirfcb {
  79.     char    dummy;
  80.     char    exset;
  81.     char    res[5];
  82.     char    flags;
  83.     char    drive;
  84.     char    fname[8];
  85.     char    fext[3];
  86.     char    gap[17];
  87.     char    size[4];
  88. } ExDirFCB;
  89.  
  90. typedef struct exdosfcb {
  91.     char    dummy;
  92.     char    exset;
  93.     char    res[5];
  94.     char    flags;
  95.     char    drive;
  96.     char    fname[8];
  97.     char    fext[3];
  98.     unsigned curblk;
  99.     unsigned recsize;
  100.     long    size;
  101.     unsigned date;
  102.     char    reserved[10];
  103.     char    relrec;
  104.     char    record[4];
  105. } ExFCB;
  106.  
  107. extern    int    BrkFlag;
  108.  
  109. extern    int    mode, bdrive, firstcopy;
  110.  
  111. extern    char    pathstring[256];
  112. extern    char    privmask;
  113.  
  114. int    _fmode = 0x8000;
  115.  
  116. extern    int    listcount;
  117.  
  118.  
  119. typedef    struct    liststruct {
  120.     struct liststruct *link;
  121.     char    name[12]; /* 1 too big for even allocation */
  122.     char    marked;
  123.     char    flags;
  124.     long    size;    /* size of file in bytes */
  125.     unsigned units;    /* size of file in allocation units */
  126. } LISTNODE;
  127.  
  128. #define     LISTSIZE    250
  129. extern    LISTNODE *list[LISTSIZE], *curnode;
  130.  
  131. ExFCB    sourcefile;
  132. ExFCB    destfile;
  133.  
  134.  
  135.  
  136. extern    int    curtrack,dstat,istat;
  137.  
  138.  
  139. struct    fhead {
  140.     char    fflag;
  141.     char    fname[11];
  142.     int    boffset;
  143.     int    blklen;
  144.     char    data[1];
  145. };
  146.  
  147. struct fcbstruct {
  148.     char        fcbdrive;
  149.     char        fcbname[11];
  150.     int        fblock;
  151.     int        recsize;
  152.     unsigned    fsizelow;
  153.     unsigned    fsizehigh;
  154.     char        reserved[12];
  155.     char        currec;
  156. };
  157.  
  158.  
  159. char    *dirhead = " DIRECTORY      ";
  160. char    twork[8208] ={0};
  161.  
  162.  
  163. acheckbreak()
  164. {
  165.     char    ch;
  166.     ChkKey();
  167.     if (BrkFlag) {
  168.         cprintf("\r\n\7");
  169.         if (yes("Cancel Archive session? (Y/N) ")) {
  170.             if (!fileswritten) {
  171.                 backmarks(1);
  172.                 backrecs(1);
  173.             }
  174.             marktape(); marktape();
  175.             abort();
  176.         }
  177.     BrkFlag = 0;
  178.     }
  179. }
  180.  
  181.  
  182.  
  183. int    imin();
  184. unsigned umin();
  185. long    lmin();
  186.  
  187.  
  188. writelist()
  189. {
  190.     char    test[20],ch;
  191.     int    stat, reuse, i, proceed;
  192.     unsigned u;
  193.  
  194.     if (!listcount) return;
  195.  
  196.     /* SORT FILE LIST IN ASCENDING SIZE */
  197.     sortlist();
  198.     unitsize = 8192;
  199.     calcunits();
  200.  
  201.     dotape();
  202.  
  203.     cprintf("\r\n");
  204. }
  205.  
  206.  
  207. char    btime[7];
  208.  
  209. /*
  210.     dotape() WILL WRITE FILES TO TAPE IN LARGEST TO SMALLEST ORDER,
  211.     SKIPPING IF NECESSARY TO PACK SMALLER FILES AT END OF TAPE.
  212. */
  213. dotape()
  214. {
  215.     char    i;
  216.     int    writecount;
  217.     unsigned ccode, splitting;
  218.  
  219.     cprintf("     Archiving: ");
  220.  
  221.     timedate(btime);
  222.  
  223. onemoretime:
  224.     while (logheader(btime)) {
  225.         cprintf("\r\n\7Tape is full or otherwise unusable.\r\n");
  226.         tapesetup();
  227.     }
  228.  
  229.     writecount = 0;
  230.     splitting = FALSE;
  231.     fileswritten = FALSE;
  232.  
  233.     i = LISTSIZE;
  234.     while (i--) {
  235.         acheckbreak();
  236.         if (list[i]) {
  237.         if (list[i]->size == 0L) ccode = -1; /* IGNORE ZERO FILES */
  238.         else if (list [i]->name [0] != 0x80) {
  239.             if (splitting) {
  240.                     ccode = writefile(i, twork,&writecount,writecount);
  241.                 splitting = FALSE;
  242.             }
  243.             else {
  244.                 if (writecount && list[i]->units > writecount) continue;
  245.                 putch('*');
  246.                 ccode = writefile(i, twork, &writecount,0);
  247.             }
  248.         }
  249.         else {putch ('+'); ccode = 0;} /* skip dummy rights entry */
  250.  
  251.         switch(ccode) {
  252.         case -3: /* WRITE FAILURE */
  253.         case -2: /* WRITE FAILURE */
  254.             error ("FATAL ERROR:  Error writing to tape.");
  255.             marktape(); marktape(); /* WRITE EOT */
  256.             myexit(0);
  257.             break;
  258.         case  0: /* FILE WAS WRITTEN OK; REMOVE FROM LIST AND GO ON */
  259.             fileswritten = TRUE;
  260.         case -1: /* UNABLE TO OPEN FILE, SKIPPED */
  261.             free(list[i]);
  262.             listcount--;
  263.             list[i] = 0x0000;
  264.             break;
  265.         case  1:
  266.             switch(split(i, writecount)) {
  267.             case 1:    /* FILE SKIPPED, CONTINUE TO NEXT */
  268.                 clrfile(&sourcefile.exset);
  269.                 if (!writecount) i=0;    /* No more space */
  270.                 break;
  271.             case 2: /* ADVANCE TO NEXT TAPE BEFORE GOING ON */
  272.                 i++; /* Do same file over again */
  273.                 if (!fileswritten) {
  274.                     backmarks(1);
  275.                     backrecs(1);
  276.                 }
  277.                 marktape(); marktape(); /* EOT */
  278.                 cprintf("\r\n");
  279.                 tapesetup();
  280.                 while (logheader(btime)) {
  281.                     cprintf("\7Tape is full or otherwise unusable.\r\n");
  282.                     tapesetup();
  283.                 }
  284.                 writecount = 0;
  285.                 fileswritten = FALSE;
  286.                 break;
  287.             case 3: /* FILE WAS SPLIT, need to continue next seg */
  288.                 i++;
  289.                 cprintf("\r\n");
  290.                 tapesetup();
  291.                 while (logheader(btime)) {
  292.                     cprintf("\7Tape is full or otherwise unusable.\r\n");
  293.                     tapesetup();
  294.                 }
  295.                 splitting = TRUE;
  296.                 fileswritten = FALSE;
  297.                 slogentry(i-1);
  298.                 break;
  299.             }
  300.         }
  301.         }
  302.     }
  303.     /* IF STILL HAVE FILES, THEN MUST ERASE HEADER */
  304.     if (!fileswritten) {
  305.         backmarks(1);
  306.         backrecs(1);
  307.     }
  308.     if (listcount) {
  309.         marktape(); marktape(); /* EOT */
  310.         cprintf("\r\n");
  311.         tapesetup();
  312.         goto onemoretime;
  313.     }
  314.     else {
  315.         marktape(); marktape();
  316.         backmarks(2);
  317.     }
  318. }
  319.  
  320.  
  321. split(fnum, writecount)
  322.     unsigned fnum, writecount;
  323. {
  324.     if (writecount > 32) return (3); /* SPLIT */
  325.     else return (1); /* TRY NEXT FILES */
  326. }
  327.  
  328.  
  329. logheader(time)
  330.     char    *time;
  331. {
  332.     char    ttext[65], ccode;
  333.  
  334.     gentime(time, ttext);
  335.     ccode = wdirhead(twork, pathstring, ttext);
  336.     if (ccode) return (ccode);
  337.  
  338.     if (printlog) {
  339.         printstr("  Files archived ");
  340.         printstr(ttext);
  341.         printstr("\r\n");
  342.     }
  343.  
  344.     return (0);
  345. }
  346.  
  347.  
  348. unsigned smallest()
  349. {
  350.     int    i;
  351.     unsigned u;
  352.  
  353.     i = 0;
  354.     while ((list[i] == 0) && (i < LISTSIZE)) i++;
  355.     if (i == LISTSIZE) return (0);
  356.     else return (list[i]->units);
  357. }
  358.  
  359. /* SORT list FROM SMALLEST SIZE TO LARGEST SIZE */
  360. sortlist()
  361. {
  362.     int    i, j, k;
  363.     LISTNODE *transfer;
  364.     long    minimum;
  365.  
  366.     for(i=0; i < listcount; i++) {
  367.         minimum = list[i]->size;
  368.         k = i;
  369.         for(j=i+1; j < listcount; j++) {
  370.             if (list[j]->size < minimum) {
  371.                 k = j; 
  372.                 minimum = list[j]->size;
  373.             }
  374.         }
  375.         if (k != i) {
  376.             transfer = list[k];
  377.             list[k] = list[i];
  378.             list[i] = transfer;
  379.         }
  380.     }
  381. }
  382.  
  383. calcunits()
  384. {
  385.     int    i;
  386.  
  387.     i = LISTSIZE;
  388.     while (i) {
  389.         i--;
  390.         if (list[i] == 0) continue;
  391.         list[i]->units = (unsigned) ((list[i]->size + 
  392.             (long)(unitsize-1)) / (long) unitsize);
  393.     }
  394. }
  395.  
  396. /* CLEAR MARKS ON FILES SO THAT RE-EVALUATION CAN BE PERFORMED FROM SCRATCH */
  397. clearmarks()
  398. {
  399.     unsigned i;
  400.  
  401.     for (i= 0; i < LISTSIZE; i++) {
  402.         list[i]->marked = FALSE;
  403.     }
  404. }
  405.  
  406.  
  407.  
  408.  
  409. setflags(fnum, setmask, clrmask)
  410. char    setmask, clrmask;
  411. int    fnum;
  412. {
  413.     ExFCB    search;
  414.     ExDirFCB found;
  415.  
  416.     setmem(&search, sizeof(ExFCB), 0);
  417.     search.exset = 0xFF;
  418.     search.flags = 0x06;
  419.     search.drive = VARPATH + 1;
  420.     movmem(list[fnum]->name, search.fname, 11);
  421.     setDTA(&found.exset);
  422.     if (search1(&search.exset)) return; /* ERROR, forget it */
  423.     found.gap[0] |= setmask;
  424.     found.gap[0] &= ~clrmask;
  425.     if (FileAtt(&found.exset, found.gap[0])) /* ERROR */ ;
  426. }
  427.  
  428.  
  429. dopensource(fnum)
  430. int    fnum;
  431. {
  432.     char    ch, sourcename[20];
  433.     int    i, c, stat;
  434.  
  435.     setmem(&sourcefile, sizeof(ExFCB), 0);
  436.     sourcefile.exset = 0xFF;
  437.     sourcefile.flags = 0x06;
  438.     sourcefile.drive = VARPATH + 1;
  439.     movmem(list[fnum]->name, sourcefile.fname, 11);
  440.     if (logfile(&sourcefile.drive)) {
  441.         error("Network file list full.");
  442.         myexit(0);
  443.     }
  444.     while (lockfset(0)) {
  445.         cprintf("\r\nFile ");
  446.         showfile(&sourcefile.drive);
  447.         cprintf("is in use by another station.  ");
  448.         ch = 'x';
  449.         while (ch != 'S' && ch != 'R') {
  450.             cprintf("Skip or Retry? ");
  451.             ch = getstr(inline, 5);
  452.             if (ch == 3) {fclose(log); abort();}
  453.             if (!ch) {ch = 'R'; cprintf("Retry");}
  454.             ch = toupper(ch);
  455.             cprintf("\r\n");
  456.         }
  457.         if (ch == 'S') {
  458.             clrfile(&sourcefile.drive);
  459.             inuselog(sourcefile.fname); /* make note in print log */
  460.             return (FALSE);
  461.         }
  462.     }
  463.  
  464.     /* OPEN FILE FOR HIGH LEVEL BUFFERED I/O */
  465.     stat = openfile(&sourcefile.exset);
  466.     if (stat) return (FALSE); /* FILE WAS DELETED BEFORE I LOCKED IT */
  467.     sourcefile.recsize = 1;
  468.     return (TRUE);
  469. }
  470.  
  471.  
  472. lprint(string)
  473. char    *string;
  474. {
  475.     cprintf(string);
  476.     if (printlog) printstr(string);
  477. }
  478.  
  479. printstr(text)
  480. char    *text;
  481. {
  482.     while (*text) prnout(*text++);
  483. }
  484.  
  485. prnline()
  486. {
  487.     char    line[80];
  488.  
  489.     setmem(line, 79, '=');
  490.     line[79] = 0;
  491.     printstr(line);
  492.     printstr("\r\n");
  493. }
  494.  
  495.  
  496. sendbanner()
  497. {
  498.     char    spl[25], srb[100];
  499.  
  500.     spl[0] = 21;
  501.     spl[1] = 0;
  502.     spl[2] = 2;
  503.     spl[3] = 0x80 | 0x40 | 0x20; /* Banner, Delete, Tabs */
  504.     spl[4] = 8;
  505.     spl[5] = nprinter;
  506.     spl[6] = logcopies;
  507.     spl[7] = 0;
  508.     strcpy(&spl[8], "\3ARCHIVE LOG   ");
  509.     srb[0] = 98;
  510.     srb[1] = 0;
  511.     if (SpoolReq(spl, srb)) {
  512.         cprintf("Error sending spooler flags -- log report cancelled.\r\n\7");
  513.         printlog = FALSE;
  514.     }
  515. }
  516.  
  517. int    countprinters()
  518. {
  519.     char    spl[30], srb[100];
  520.     int    p = 4;
  521.  
  522.     spl[0] = 2;
  523.     spl[1] = 0;
  524.     spl[2] = 6;
  525.     spl[3] = p;
  526.     srb[0] = 98;
  527.     srb[1] = 0;
  528.     while (SpoolReq(spl, srb) != 0 && p) {
  529.         p--;
  530.         spl[3]--;
  531.     }
  532.     return (p+1);
  533. }
  534.  
  535.  
  536. configlog()
  537. {
  538.     char    ans[10], ch;
  539.     int    pnum;
  540.  
  541.     printlog, spool = FALSE;
  542.     if (!yes("Do you want to print a log report of this session? (Y/N) ")) 
  543.         return;
  544.     else printlog = TRUE;
  545.  
  546.     ans[0] = 'x';
  547.     while (ans[0] != 'N' && ans[0] != 'L') {
  548.         cprintf("Print to Local printer or Network spooler? (L/N) ");
  549.         ch = getstr(ans, 7);
  550.         if (ch == 3) abort();
  551.         if (!ch) {ans[0] = 'N'; cprintf("Network");}
  552.         cprintf("\r\n");
  553.         conupper(ans);
  554.         if (ans[0] == 'N') spool = TRUE;
  555.     }
  556.  
  557.     if (!spool) {ploghead(); return;}
  558.  
  559.     /* request printer # and # of copies */
  560.     pnum = countprinters();
  561.     if (pnum > 1) {
  562.         nprinter = 9;
  563.         while (nprinter >= pnum || nprinter < 0) {
  564.             cprintf("Select network printer: (0 - %d) ",pnum-1);
  565.             getstr(ans, 1);
  566.             if (ans[0] == 3) abort();
  567.             if (!ans[0]) {ans[0] = '0'; cprintf("0");}
  568.             cprintf("\r\n");
  569.             nprinter = ans[0] - '0';
  570.         }
  571.     }
  572.     else nprinter = 0; /* only one printer, so don't ask */
  573.  
  574.     logcopies = 10;
  575.     while (logcopies < 1 || logcopies > 9) {
  576.         cprintf("Number of copies: (1-9) ");
  577.         getstr(ans, 1);
  578.         if (ans[0] == 3) abort();
  579.         if (!ans[0]) {ans[0] = '1'; cprintf("1");}
  580.         cprintf("\r\n");
  581.         logcopies = ans[0] - '0';
  582.     }
  583.  
  584.     /* START PRINT MODE */
  585.     modLST(0);
  586.     sendbanner();
  587.     ploghead();
  588. }
  589.  
  590. ploghead()
  591. {
  592.     char    t[7], buff[80];
  593.     timedate(t); /* get system time */
  594.     gentime(t, buff);
  595.     if (!spool) printstr("\14"); /* form feed */
  596.     prnline(); 
  597.     printstr("Archive Log Report for session started ");
  598.     printstr(buff);
  599.     printstr("\r\nAny files listed below were archived to ");
  600.     printstr("the backup tape.\r\n");
  601.     prnline(); 
  602.     printstr("\r\n");
  603. }
  604.  
  605. tapehead(aflag)
  606. int    aflag;
  607. {
  608.     if (!printlog) return;
  609.     prnline();
  610.     if (aflag) 
  611.         printstr("APPENDING TO A TAPE\r\n");
  612.     else    printstr("BEGINNING A NEW TAPE\r\n");
  613.     prnline();
  614.     printstr("\r\n\r\n");
  615. }
  616.  
  617.  
  618. logentry(fnum)
  619. int    fnum;
  620. {
  621.     char    orig[20], out[80];
  622.     int    ix = 0;
  623.  
  624.     movmem(list[fnum]->name, orig, 11);
  625.     orig[11] = 0;
  626.     ix += sprintf(out, "  %11s %3s", orig, &actarget[8]);
  627.  
  628.     orig[0] = orig[1] = 0x20;
  629.     orig[2] = 0; 
  630.     if (list [fnum]->flags) sprintf (orig, "%2x", list [fnum]->flags);
  631.  
  632.     sprintf(&out[ix], "%2s                \15\12", orig);
  633.     if (printlog) printstr(out);
  634. }
  635.  
  636. skiplog(name)
  637. char    *name;
  638. {
  639.     char    temp[20];
  640.  
  641.     movmem(name, temp, 11);
  642.     temp[11] = 0;
  643.     if (!printlog) return;
  644.     printstr("> ");
  645.     printstr(temp);
  646.     printstr("  NOT archived.  Skipped to avoid file splitting.\r\n");    
  647. }
  648.  
  649. inuselog(name)
  650. char    *name;
  651. {
  652.     char    temp[20];
  653.  
  654.     movmem(name, temp, 11);
  655.     temp[11] = 0;
  656.     if (!printlog) return;
  657.     printstr("> ");
  658.     printstr(name);
  659.     printstr("  NOT archived.  File was in use by another station.\r\n");
  660. }
  661.  
  662.  
  663. slogentry(fnum)
  664. int    fnum;
  665. {
  666.     char    orig[20], out[80];
  667.     int    ix = 0;
  668.  
  669.     if (!printlog) return;
  670.  
  671.     movmem(list[fnum]->name, orig, 11);
  672.     orig[11] = 0;
  673.     ix += sprintf(out, "* %11s %3s", orig, &actarget[8]);
  674.  
  675.     orig[0] = orig[1] = 0x20;
  676.     orig[2] = 0; 
  677.     if (list [fnum]->flags) sprintf (orig, "%2x", list [fnum]->flags);
  678.  
  679.     sprintf(&out[ix], "%2s\15\12", orig);
  680.     printstr(out);
  681. }
  682.  
  683.  
  684. static     char    *daytab[] = {
  685.     "Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
  686.  
  687. static    char    *monthtab[] = {
  688.     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  689.  
  690.  
  691. gentime(in, out)
  692. char    *in, *out;
  693. {
  694.     int    hour, ix = 0;
  695.     char    year[4];
  696.  
  697.     ix = sprintf(out, "%9s, ",daytab[in[6]]); /* day of week */
  698.     ix += sprintf(&out[ix], "%3s %2d, ", monthtab[in[1]-1],in[2]);
  699.     sprintf(year, "%2d", in[0]);
  700.     if (in[0] < 10) year[0] = '0';
  701.     if (in[0] < 82) ix += sprintf(&out[ix], "20%2s  ", year);
  702.     else ix += sprintf(&out[ix], "19%2s  ", year);
  703.  
  704.     hour = in[3];
  705.     if (hour > 12) hour -= 12;
  706.     if (!hour) hour = 12;
  707.     ix += sprintf(&out[ix], "%2d:", hour);
  708.     if (in[4] < 10) 
  709.         ix += sprintf(&out[ix], "0%1d ", in[4]);
  710.     else    ix += sprintf(&out[ix], "%2d ", in[4]);
  711.     if (in[3] >= 12) sprintf(&out[ix], "pm");
  712.     else sprintf(&out[ix], "am");
  713. }
  714.  
  715.  
  716.  
  717. int wdirhead(buff,dir,date)
  718. char *buff,*dir,*date;
  719. {
  720.     char    *s1,*s2;
  721.     int    i;
  722.  
  723.     s1 = dirhead;
  724.     s2 = buff;
  725.     while (*s1) *s2++ = *s1++;
  726.     s1 = date;
  727.     for (i=0;i<64;i++) {
  728.         if (*s1) *s2++ = *s1++;
  729.         else *s2++ = 0;
  730.     }
  731.     s1 = dir;
  732.     while (*s1) *s2++ = *s1++;
  733.     *s2++ = 0;
  734.  
  735.     if (saverights) {
  736.         CopyTrustees (s2);
  737.         if (printlog) printstr ("(Directory rights and trustee lists saved)\r\n");
  738.     }
  739.     else *s2++ = 0;    /* put in first byte to indicate NO stuff saved */
  740.  
  741.     marktape();
  742. eotcheck:
  743.     if (dstat & 4) {
  744.         marktape();
  745.         if (curtrack != 3) {
  746.             seltrack(curtrack+1);
  747.             rewindtape();
  748.             marktape();
  749.         }
  750.         else {
  751.             cprintf("\r\n");
  752.             tapesetup();
  753.             marktape();
  754.         }
  755.     }
  756.     if (writetape(buff)) return (-1);
  757.     if (writestat()) {
  758.         if (((istat & 0x30) == 0x10) && (dstat &4)) goto eotcheck;
  759.         return (-1);
  760.     }
  761.     return (marktape());
  762. }
  763.  
  764.  
  765. int writefile(fnum,buff,bcnt,soffset)
  766.     unsigned fnum;
  767.     struct      fhead *buff;
  768.     unsigned *bcnt;
  769.     unsigned soffset;
  770. {
  771.     char    *s1,*s2;
  772.     struct    fcbstruct *fcb;
  773.     int    numblks,lastlen,i;
  774.  
  775.     if (list [fnum]->name [0] == 0x80) {numberout++; return (0);}
  776.  
  777.     s1=list[fnum]->name;
  778.     s2=buff->fname;
  779.     for (i=0;i<11;i++) *s2++ = *s1++;
  780.     buff->fflag = list[fnum]->flags;
  781.     buff->boffset = buff->blklen = 0;    
  782.  
  783.     if (!dopensource(fnum)) return(-1);
  784.  
  785.     fcb = (struct fcbstruct *) &sourcefile.drive;
  786.  
  787.     lastlen = fcb->fsizelow & 0x1fff;
  788.     numblks = (fcb->fsizelow >> 13) | (fcb->fsizehigh << 3);
  789.     if (lastlen) numblks++;
  790.     fcb->fblock = 0;    
  791.     fcb->recsize = 8192;
  792.     fcb->currec = 0;
  793.     SetDTA(buff->data);
  794.     if (soffset) {
  795.         numblks -= soffset;
  796.         fcb->currec = soffset & 0x7f;
  797.         fcb->fblock = soffset >> 7;
  798.         buff->boffset = soffset;
  799.     }
  800.     SeqRead(fcb);
  801.     while (numblks--) {
  802.         if (numblks==0) {
  803.             buff->blklen = lastlen;
  804.             buff->fflag |= LASTBIT;
  805.         }
  806.         if (dstat & 4) { /* EOT */
  807.             marktape();
  808.             marktape();
  809.             if (curtrack != 3) {
  810.                 seltrack(curtrack +1);
  811.                 rewindtape();
  812.             }
  813.             else {
  814.                 *bcnt= buff->boffset;
  815.                 if (backmarks(2)) {cp ('A');return(-2);}
  816.                 if (*bcnt) {
  817.                     if (backrecs(*bcnt)) {cp('B');return(-2);}
  818.                 }    
  819.             return(1);
  820.             }
  821.         }
  822.         if (writetape(buff)) {cp ('C');return (-2);}
  823.         SeqRead(fcb);
  824.         buff->boffset++;
  825.         if (writestat()) {
  826.             if (((istat & 0x30) == 0x10) && (dstat & 4)) { /*EOT*/
  827.                 buff->boffset--;                
  828.                 numblks++;
  829.                 fcb->currec=buff->boffset & 0x7f;
  830.                 fcb->fblock=buff->boffset >> 7;
  831.                 SeqRead(fcb);
  832.             }
  833.             else {cp ('D'); return(-3);}
  834.         } else buff->fflag=0;
  835.     }
  836.  
  837.     setflags(fnum, 0, BACKUPBIT); /* clear bit, indicating backed up */
  838.     clrfile(&sourcefile.exset);
  839.  
  840.     numberout++;
  841.  
  842.     logentry(fnum);
  843.  
  844.     return (0);
  845. }
  846.  
  847. tapesetup()
  848. {
  849.     char    ch;
  850.  
  851. newtape:
  852. cprintf("1 tapesetup\n\r");
  853.     resettape();
  854. cprintf("2 tapesetup\n\r");
  855.     rewindtape();
  856. cprintf("3 tapesetup\n\r");
  857.     cprintf(
  858.     "Prepare the backup tape in the Alloy unit and press any key to continue.\7\r\n");
  859.     ch = getch();
  860.     if (ch == 0x03) myexit();
  861.  
  862.     resettape();
  863.     rewindtape();
  864.  
  865.     /* CHECK WRITE PROTECT */
  866.     if (!(dstat & 1)) {
  867.         cprintf("\7This tape is write-protected.\r\n");
  868.         goto newtape;
  869.     }
  870.  
  871.     if (yes("Do you want to append to the end of this tape? (Y/N) ")) {
  872.         cprintf("Searching for the end of the tape.\r\n");
  873.         if (findEOT(twork)) {
  874.             cprintf("\7Unable to find End-of-tape mark.\r\n");
  875.             goto newtape;
  876.         }
  877.         else tapehead(TRUE);
  878.     }
  879.     else {
  880.         cprintf("This will destroy any data on the tape.\r\n");
  881.         if (!yes("Do you wish to continue? (Y/N) ")) goto newtape;
  882.         cprintf("Initializing tape -- please wait.\r\n");
  883.         if (inittape(twork)) {
  884.             cprintf("\7Unable to initialize tape.\r\n");
  885.             goto newtape;
  886.         }
  887.         else tapehead(FALSE);
  888.     }
  889. }
  890.  
  891. cp (letter)
  892.     char    letter;
  893. {
  894.     cprintf ("Check point %c\7\7\7\r\n", letter);
  895. }
  896.